#include "analysis.h"
#include <QDebug>
#include <QHashIterator>
#include <QFileDialog>
#include "logfiledialog.h"
#include <QMessageBox>
#include <QProgressDialog>
/**This class handles the entire analysis of zero or more log files*/

Analysis::Analysis(QWidget* parent)
{
    m_parent =(AnalysisForm*) parent;
    this->m_totalNumberOfStatements=0;
    this->m_totalRunningTime=0;
    qDebug()<<"new analysis...";
    this->m_defaultLineValidator = NULL;
    // do this for now...
    this->m_defaultLineValidator = new LineValidator;
    m_defaultLineValidator->setInValidLinePattern("^(NOTICE:|ERROR:|STATEMENT:LOG:  connection).*");
    m_defaultLineValidator->setValidLinePattern("^LOG:  duration: \\d+\\.\\d+ ms  statement: .*");
}

void Analysis::setDefaultLineValidator(LineValidator& tmpVL)
{
    if (this->m_defaultLineValidator != NULL)
        *(this->m_defaultLineValidator) = tmpVL;
    else
    {
        this->m_defaultLineValidator = new LineValidator();
        if (this->m_defaultLineValidator!= NULL)
            *(this->m_defaultLineValidator) = tmpVL;
    }
}

void Analysis::importLogFile(QString fileName)
{
    QFile file(fileName);
    qint64 totalsize = file.size();
    qint64 bytesProcessed= 0; // how much data have we processed
    int lastpercent=0,newpercent=0;

    if (! file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QMessageBox::critical(0,QString("No analysis started"), QString("You have to have an active analysis to be able to add a new logfile to the analysis."));
        exit(2);
    }
    else
    {
        //read the loggfile
        QTextStream in(&file);
        QString statement;
        bool lastLineHasContent=false;
        QString lastLine="";
        QString line;

        QProgressDialog progressDialog(QString("Importing data. Please wait"),QString("Abort"),0,100, m_parent);
        progressDialog.setWindowModality(Qt::WindowModal);

        while (!in.atEnd() )
        {
            line = in.readLine();
            bytesProcessed+=line.size();

            if (lastLineHasContent)
            {
                if (this->m_defaultLineValidator->isValidLogLine(line)) // finish last line and start with this new one
                {
                    this->addNewLogLine(lastLine); // add this line
                    newpercent=(int)(100*bytesProcessed/totalsize);
                    if (newpercent!=lastpercent)
                    {
                        progressDialog.setValue(newpercent);
                        lastpercent=newpercent;
                    }
                    lastLine = line.trimmed(); // start with new line
                    lastLineHasContent = true;
                }
                else if (m_defaultLineValidator->isInValidLogLine(line))
                {
                    this->addNewLogLine(lastLine);
                    newpercent=(int)(100*bytesProcessed/totalsize);
                    if (newpercent!=lastpercent)
                    {
                        progressDialog.setValue(newpercent);
                        lastpercent=newpercent;
                    }
                    // just ignore this line.
                    lastLine.clear();
                    lastLineHasContent = false;
                }
                else // this is continuation of last line
                {
                    lastLine.append(line.trimmed());
                }
            }
            else // we have no content, might be after other block than a valid line or when we have first line
            {
                if (m_defaultLineValidator->isValidLogLine(line)) // first real line?
                {
                    lastLine = line.trimmed();
                    lastLineHasContent=true;
                }
            }
        }
        // add the very last line we read if we have a valid line already
        if (lastLineHasContent)
        {
            this->addNewLogLine(lastLine);
            newpercent=(int)(100*bytesProcessed/totalsize);
            if (newpercent!=lastpercent)
            {
                progressDialog.setValue(newpercent);
                lastpercent=newpercent;
            }
        }
        if (progressDialog.wasCanceled())
        {
        exit(3);
        }
        progressDialog.setValue(100);
    }
    this->setDurationStatistics();
    this->setStatementStatistics();
    m_parent->toggleStatementSort(true);
}

void Analysis::addNewLogLine(QString line)
{
    qreal duration;
    QString statement;
    if (this->m_defaultLineValidator->extractDurationAndStatement(line,duration,statement))
    {
        // anonymize the statement
        this->m_defaultLineValidator->annonymizeStatement(statement);

        // add the statement to the statistics
        m_totalNumberOfStatements++;
        this->m_totalRunningTime += duration;

        Stat* tmp;
        if (!m_statistics.contains(statement))
        {
            tmp=new Stat;
            tmp->add(duration);
            this->m_statistics.insert(statement,tmp);
        }
        else
        {
            tmp = this->m_statistics.value(statement);
            tmp->add(duration);
        }
    }
}

void Analysis::viewResult()
{
    m_parent->clearAll();
    QHashIterator<QString, Stat*> it(m_statistics);
    while (it.hasNext())
    {
        it.next();
        m_parent->addStatement(it.value()->nrOfPosts(),it.value()->getSum(),QString::number(it.value()->getMin())+QString("/")+QString::number(it.value()->getAverage())+QString("/")+QString::number(it.value()->getMax()),it.key());
    }
}

void Analysis::addNewLogFile()//QWidget* parent)
{
    qDebug()<<"starting addNewLogFile";
    // get file name
    QString fileName = QFileDialog::getOpenFileName(m_parent,QString("Open logfile")); //TODO: set default directory?
    if (! fileName.isEmpty() && QFile::exists(fileName) )
    {
        // set linevalidation
        LogfileDialog* lfdptr = NULL;
qDebug()<<"creating new LogfileDialog";
        lfdptr = new LogfileDialog(m_parent,this->m_defaultLineValidator,fileName);
        lfdptr->showLineValidatorData();
qDebug()<<"created new LogfileDialog";
        if (lfdptr->exec()== QDialog::Accepted) //no error
        {
            qDebug()<<"ok clicked";
            //parse
            this->importLogFile(fileName);
            //add the data
        }
        else
        {
            qDebug()<<"cancel clicked";
            //show error?
        }
        delete lfdptr;
        this->viewResult();
    }
}

void Analysis::setName(QString name)
{
    m_name = name;
}

void Analysis::setStatementStatistics()
{
    m_parent->setStatementStatistics(this->m_totalNumberOfStatements,this->m_statistics.size());
}

void Analysis::setDurationStatistics()
{
    m_parent->setDurationStatistics(this->m_totalRunningTime,this->m_totalRunningTime/(qreal)this->m_totalNumberOfStatements);
}


void Analysis::retrieveHistoric(QString statement)
{
    if (this->m_statistics.contains(statement))
    {
        m_parent->setMinHistoric(this->m_statistics.value(statement)->getMin());
        m_parent->setMaxHistoric(this->m_statistics.value(statement)->getMax());
        m_parent->setCurrentStat(this->m_statistics.value(statement)); //this is better than sending a signal, I think!
        emit SIG_sendHistoric(this->m_statistics.value(statement));
    }
}

void Analysis::retrieveFrequency(QString statement)
{
    if (this->m_statistics.contains(statement))
    {
        m_parent->setMinFrequency(this->m_statistics.value(statement)->getMin());
        m_parent->setMaxFrequency(this->m_statistics.value(statement)->getMax());
        m_parent->setCurrentStat(this->m_statistics.value(statement));
        emit SIG_sendFrequency(this->m_statistics.value(statement));
    }
}

void Analysis::doConnections()
{
    connect(this,SIGNAL(SIG_sendFrequency(Stat*)),m_parent,SLOT(plotFrequency(Stat*)));
    connect(this,SIGNAL(SIG_sendHistoric(Stat*)),m_parent,SLOT(plotHistoric(Stat*)));
    connect(m_parent,SIGNAL(SIG_getFrequency(QString)),this,SLOT(retrieveFrequency(QString)));
    connect(m_parent,SIGNAL(SIG_getHistoric(QString)),this,SLOT(retrieveHistoric(QString)));
    m_parent->doConnections();
}
